﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Fighter.Screens;

namespace Fighter.GameContent
{
    class Teacher : Boss
    {
        private int augmentationAlertX;
        private int augmentationAlertY;
        private bool scenarioDisplayed = false;
        public bool ScenarioDisplayed
        {
            get { return scenarioDisplayed; }
            set { scenarioDisplayed = value; }
        }
        private bool orderDisplayed = false;
        public bool OrderDisplayed
        {
            get { return orderDisplayed; }
            set { orderDisplayed = value; }
        }

        /// <summary>
        /// Gets whether or not the player's feet are on the ground.
        /// </summary>


        private float movement;
        public float Movement
        {
            get { return movement; }
            set { movement = value; }
        }
        private bool isJumping;
        private bool wasJumping;
        private float jumpTime;
        private Vector2 velocity;
        private float previousBottom;
        private const float MoveAcceleration = 20000.0f;
        private const float MaxMoveSpeed = 1750.0f;
        private const float MaxJumpTime = 0.40f;
        private const float MaxFallSpeed = 550.0f;
        private const float JumpLaunchVelocity = -3500.0f;
        private bool isOnGround;
        private const float JumpControlPower = 0.14f;
        private const float GroundDragFactor = 0.48f;
        private const float GravityAcceleration = 3400.0f;
        private const float AirDragFactor = 0.58f;

        public Teacher(Level level, Vector2 position, string spriteSet, GraphicsDeviceManager graphics, int life, int zoneAlertX, int zoneAlertY)
            : base(level, position, spriteSet, graphics, life, zoneAlertX, zoneAlertY)
        {
            this.DistanceBeforeRush = 100000;
            this.augmentationAlertX = zoneAlertX;
            this.augmentationAlertY = zoneAlertY;
            isMoving = false;
            isAgressive = false;
            this.IntervalleMunition = this.IntervalleMunition / 2;
        }

        public override void Update(GameTime gameTime)
        {
            //movement = (int)direction * 1.0f;
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
            this.updateZoneAlert(this.BoundingRectangle);
            bool attacable;
            attacable = isPlayerAttacable(Level.Player.BoundingRectangle);

            if (waitTime > 0)
            {
                waitTime = Math.Max(0.0f, waitTime - (float)gameTime.ElapsedGameTime.TotalSeconds);
                if (waitTime <= 0.0f)
                {
                    // Then turn around.
                    direction = (FaceDirection)(-(int)direction);
                }
            }
            else
            {
                // Calculate tile position based on the side we are walking towards.
                float posX = Position.X + localBounds.Width / 2 * (int)direction;
                int tileX = (int)Math.Floor(posX / Tile.Width) - (int)direction;
                int tileY = (int)Math.Floor(Position.Y / Tile.Height);
                // If we are about to run into a wall or off a cliff, start waiting.
                if (Level.GetCollision(tileX + (int)direction, tileY - 4) == TileCollision.Impassable ||
                    Level.GetCollision(tileX + (int)direction, tileY - 3) == TileCollision.Impassable ||
                    Level.GetCollision(tileX + (int)direction, tileY - 2) == TileCollision.Impassable ||
                    Level.GetCollision(tileX + (int)direction, tileY - 1) == TileCollision.Impassable ||
                    Level.GetCollision(tileX + (int)direction, tileY) == TileCollision.Passable)
                {
                    if (IsAgressive)
                    {
                        isJumping = true;
                        DoJump(gameTime);
                    }
                    else
                    {
                        waitTime = MaxWaitTime;
                    }
                }
                else
                {
                    isJumping = false;
                    jumpTime = 0;
                    // Move in the current direction.
                    Vector2 velocity = new Vector2((int)direction * MoveSpeed * elapsed, 0.0f);
                    position = position + velocity;
                }
            }
            if (isAgressive)
            {
                if (attacable == true)
                {
                    if (this.IntervalleMunition == 0)
                    {
                        Rectangle cible = Level.Player.BoundingRectangle;
                        Vector2 startPositionMunition = this.Position;
                        startPositionMunition.Y -= this.BoundingRectangle.Height / 2;
                        Munition m = new Munition(Level, startPositionMunition, graphics, cible, (int)direction);
                        listMunitions.Add(m);
                        intervalleMunition++;

                    }
                    else
                    {
                        intervalleMunition++;
                        if (this.IntervalleMunition == 25) this.IntervalleMunition = 0;
                    }

                }
            }

            List<Munition> listMunitionsToRemove = new List<Munition>();
            foreach (Munition munition in listMunitions)
            {
                munition.UpdateForBoss(gameTime);
                if (munition.munitionTouched() != null)
                {
                    listMunitionsToRemove.Add(munition.munitionTouched());
                    Level.Player.OnTouch(this, gameTime);
                }

            }
            foreach (Munition munition in listMunitionsToRemove)
                listMunitions.Remove(munition);

            //ApplyPhysics(gameTime);

            // Clear input.
            //isJumping = false;
        }

        public void ApplyPhysics(GameTime gameTime)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            Vector2 previousPosition = Position;

            if (isOnGround)
            {
                velocity = new Vector2((int)direction * MoveSpeed * elapsed, 10.0f);
                position = position + velocity;
            }
            else
            {
                velocity = new Vector2((int)direction * MoveSpeed * elapsed, 5.0f);
                position = position + velocity;
            }

            // If the player is now colliding with the level, separate them.
            HandleCollisions();

            // If the collision stopped us from moving, reset the velocity to zero.
            if (Position.X == previousPosition.X)
                velocity.X = 0;

            if (Position.Y == previousPosition.Y)
                velocity.Y = 0;
        }

        private void DoJump(GameTime gameTime)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            // If the player wants to jump
            if (isJumping)
            {
                jumpTime += (float)gameTime.ElapsedGameTime.TotalSeconds;

                // If we are in the ascent of the jump
                if (jumpTime <= MaxJumpTime)
                {
                    velocity = new Vector2((int)direction * MoveSpeed * elapsed, -10.0f);
                    position = position + velocity;
                }
                else
                {
                    velocity = new Vector2((int)direction * MoveSpeed * elapsed, 10.0f);
                    position = position + velocity;
                }
            }
            else
            {
                // Continues not jumping or cancels a jump in progress
                jumpTime = 0.0f;
            }
            wasJumping = isJumping;


        }

        private void HandleCollisions()
        {
            // Get the player's bounding rectangle and find neighboring tiles.
            Rectangle bounds = BoundingRectangle;
            int leftTile = (int)Math.Floor((float)bounds.Left / Tile.Width);
            int rightTile = (int)Math.Ceiling(((float)bounds.Right / Tile.Width)) - 1;
            int topTile = (int)Math.Floor((float)bounds.Top / Tile.Height);
            int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / Tile.Height)) - 1;

            // Reset flag to search for ground collision.
            isOnGround = false;

            // For each potentially colliding tile,
            for (int y = topTile; y <= bottomTile; ++y)
            {
                for (int x = leftTile; x <= rightTile; ++x)
                {
                    // If this tile is collidable,
                    TileCollision collision = Level.GetCollision(x, y);
                    if (collision != TileCollision.Passable)
                    {
                        // Determine collision depth (with direction) and magnitude.
                        Rectangle tileBounds = Level.GetBounds(x, y);

                        if (collision == TileCollision.Finish)
                        {
                            ScreenManagers.StateManager.CurrentGameState = ScreenManagers.StateManager.GameState.Death;
                        }
                        else if (collision == TileCollision.Death)
                        {
                            ScreenManagers.StateManager.CurrentGameState = ScreenManagers.StateManager.GameState.Death;
                        }
                        else
                        {
                            Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds);
                            if (depth != Vector2.Zero)
                            {
                                float absDepthX = Math.Abs(depth.X);
                                float absDepthY = Math.Abs(depth.Y);

                                // Resolve the collision along the shallow axis.
                                if (absDepthY < absDepthX || collision == TileCollision.Platform)
                                {
                                    // If we crossed the top of a tile, we are on the ground.
                                    if (previousBottom <= tileBounds.Top)
                                        isOnGround = true;

                                    // Ignore platforms, unless we are on the ground.
                                    if (collision == TileCollision.Impassable || isOnGround)
                                    {
                                        // Resolve the collision along the Y axis.
                                        Position = new Vector2(Position.X, Position.Y + depth.Y);

                                        // Perform further collisions with the new bounds.
                                        bounds = BoundingRectangle;
                                    }
                                }
                                else if (collision == TileCollision.Impassable) // Ignore platforms.
                                {
                                    // Resolve the collision along the X axis.
                                    Position = new Vector2(Position.X + depth.X, Position.Y);

                                    // Perform further collisions with the new bounds.
                                    bounds = BoundingRectangle;
                                }
                            }
                        }
                    }
                }
            }

            // Save the new bounds bottom.
            previousBottom = bounds.Bottom;
        }
    }
}
